package  
{
	import flash.display.Sprite;
	import flash.events.MouseEvent;
	import flash.events.NetStatusEvent;
	import flash.external.ExternalInterface;
	import flash.media.Camera;
	import flash.media.Microphone;
	import flash.media.Video;
	import flash.net.NetConnection;
	import flash.net.NetStream;
	import flash.system.Security;
	
	/**
	 * ...
	 * @author LuXin
	 */
	public class Main extends Sprite 
	{
		private const CirrusAddress:String = "rtmfp://p2p.rtmfp.net";
		private const DeveloperKey:String = "eaeca5d3297c17326ac117ae-c3ed33e6ec0d";
		private const Publisher:String = "Publisher";
		private const Receiver:String = "Receiver";
		
		private const State_NotConnected:String = "State_NotConnected";
		private const State_Connecting:String = "State_Connecting";
		private const State_Connected:String = "State_Connected";
		private const State_playing:String = "State_playing";
		private const State_publishing:String = "State_publishing";
		
		
		private var userName:String = "user01";
		private var peerID:String;
		private var netConnection:NetConnection;		
		private var outgoingStream:NetStream;
		private var incomingStream:NetStream;
		private var video:Video;
		private var role:String;
		private var currentState:String = "State_NotConnected";
		
		
		public function Main() 
		{
			video = new Video();
			video.width = 320;
			video.height = 240;
			video.x = 4;
			video.y = 4;
			this.addChild(video);
				
			stateChange("*P2P VIDEO DEMO");
			stateChange("*发布方直接点击发布按钮");
			stateChange("*接收方输入发布方的64位peerID再点击接收按钮");
			
			Security.allowDomain( "*" );
			
			if (ExternalInterface.available)
			{
				ExternalInterface.addCallback("SetBroadcast", startPublish);
				ExternalInterface.addCallback("GetStatus", getCurrentState);
				ExternalInterface.addCallback("GetBroadcastID", getPublishID);
				ExternalInterface.addCallback("SetViewVideoByPeerID", startReceive);
			}
		}
		
		/*
		 * functions expose to outside
		 * 
		 * startPublish();   start to pulish 
		 * getCurrentState():int ;  return current connection state	
		 * getPublishID():String; return publisher's peer ID 
		 * startReceive(id:String); viewer receive stream
		 * */
		
		private function startPublish():void
		{
			role = Receiver;			
			connectServer();
		}
		
		private function getCurrentState():int
		{
			var state:int;
			switch(currentState)
			{				
				case State_NotConnected:
					state = 0;
					break;
				case State_Connecting:
					state = 1;
					break;
				case State_Connected:
					state = 2;
					break;
				case State_publishing:
					state = 3;
					break;
				case State_playing:
					state = 4;
					break;
				default:
					break;
			}
			return state;
		}
		
		private function getPublishID():String
		{
			return peerID;
		}
		
		private function startReceive(id:String):void 
		{
			peerID = id;
			role = Publisher;
			connectServer();
		}
		
		/*
		 * both pulisher and Receiver need to connect to server first
		 * */		
		private function connectServer():void 
		{			
			netConnection = new NetConnection();
			netConnection.addEventListener(NetStatusEvent.NET_STATUS, netConnectionHandler);
			netConnection.client = this;
			netConnection.connect(CirrusAddress, DeveloperKey);
			
			currentState = State_Connecting;
			
			stateChange("connection state ：connecting "+netConnection.uri);
		}
		
		private function netConnectionHandler(e:NetStatusEvent):void 
		{
			stateChange("connection state : " + e.info.code);
			
			switch (e.info.code)
            	{
                	case "NetConnection.Connect.Success":
                		connectSuccess();
                    	break;
                    	
                    case "NetConnection.Connect.Closed":
                    	currentState = State_NotConnected;
                    	break;
                    	
                    case "NetStream.Connect.Success":
                    	// we get this when other party connects to our outgoing stream
                    	//status("Connection from: " + event.info.stream.farID + "\n");
                    	break;
                    	
                    case "NetConnection.Connect.Failed":
                    	//stateChange("Unable to connect to " + connectUrl + "\n");
                    	currentState = State_NotConnected;
                    	break;
             	}
		}
		
		private function connectSuccess():void 
		{
			currentState = State_Connected;
			
			if (role == Publisher)
			{
				publicshStream();
				peerID = netConnection.nearID;
				stateChange("Connected, my ID: " + netConnection.nearID + "\n");
			}
			else if (role == Receiver)
			{
				receiveStream();
			}
		}
		
		private function publicshStream():void 
		{
			outgoingStream = new NetStream(netConnection, NetStream.DIRECT_CONNECTIONS);
			outgoingStream.addEventListener(NetStatusEvent.NET_STATUS, outNetStreamHandler);
			outgoingStream.publish("media");
			outgoingStream.attachAudio(Microphone.getMicrophone()); 
			outgoingStream.attachCamera(Camera.getCamera());
			
			video.attachCamera(Camera.getCamera());
							
			var o:Object = new Object
			o.onPeerConnect = function(caller:NetStream):Boolean
			{
				stateChange("Callee connecting to media stream: " + caller.farID + "\n");						           			
				return true; 
			}
			outgoingStream.client = o;
		}	
		
		private function receiveStream():void
		{			
			incomingStream = new NetStream(netConnection, peerID);
			incomingStream.addEventListener(NetStatusEvent.NET_STATUS, inNetStreamHandler); 
			incomingStream.play("media");
			
			video.attachNetStream(incomingStream);				
		}
		
		private function outNetStreamHandler(e:NetStatusEvent):void 
		{
			stateChange("connection state : " + e.info.code);
			if (e.info.code == "NetStream.Connect.Success")
			{
				currentState = State_publishing;
			}
		}
		
		private function inNetStreamHandler(e:NetStatusEvent):void 
		{
			stateChange("connection state : " + e.info.code);
			if (e.info.code == "NetStream.Connect.Success")
			{
				currentState = State_playing;
			}
		}
		
		private function stateChange(str:String):void
	    {
			//tt.textField.appendText(str + "\n")
			trace(str);
		}
		
	}

}